{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "cedf868076a2"
   },
   "source": [
    "##### Copyright 2020 The Cirq Developers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "cellView": "form",
    "id": "906e07f6e562"
   },
   "outputs": [],
   "source": [
    "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bNlUyYQcgMF-"
   },
   "source": [
    "# Ion Device Class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8478d245fbe2"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://www.example.org/cirq/tutorials/educators/ion_device\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on QuantumLib</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/master/docs/tutorials/educators/ion_device.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/master/docs/tutorials/educators/ion_device.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/tutorials/educators/ion_device.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "f3591bc2d8e6"
   },
   "source": [
    "The `IonDevice` represents a trapped ion quantum computer with all-to-all qubit connectivity.  The number of qubits as well as the duration of gates and measurements are specified by the user when creating an ion device.\n",
    "\n",
    "Two-qubit gates are implemented by an Ising-type coupling known as the *Mølmer–Sørensen* gate. The Mølmer–Sørensen gate couples ions through the shared motional modes of the ion chain.  The ion motion and internal state decouples at the end of each gate. The `IonDevice` class assumes this decoupling is perfect and does not explicitly model the ion motion. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "GTjMbjyAfJCK"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install cirq --quiet\n",
    "    print(\"installed cirq.\")\n",
    "    import cirq\n",
    "\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "v3YMaPw1hfV_"
   },
   "source": [
    "## Defining an `IonDevice`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8691c551a2de"
   },
   "source": [
    "To define an `IonDevice`, we specify\n",
    "\n",
    "- The set of qubits in the device,\n",
    "- The duration of single-qubit gates,\n",
    "- The duration of two-qubit gates, and\n",
    "- The duration of measurement gates.\n",
    "\n",
    "The code below creates an `IonDevice` with four qubits in a linear array. The durations we use for each type of gate are reasonable order-of-magnitude estimates, though they will differ for different trapped ion computers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "On6Wrh3XhSPO"
   },
   "outputs": [],
   "source": [
    "\"\"\"Create an IonDevice.\"\"\"\n",
    "ion_device = cirq.IonDevice(\n",
    "    qubits=cirq.LineQubit.range(4),\n",
    "    oneq_gates_duration=cirq.Duration(micros=10),\n",
    "    twoq_gates_duration=cirq.Duration(micros=200),\n",
    "    measurement_duration=cirq.Duration(micros=100)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4e6219ddb8d1"
   },
   "source": [
    "We can view some properties of the `ion_device` as shown below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "18dc0362040d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ion Device:\n",
      " 0───1───2───3\n",
      "\n",
      "Qubits in the IonDevice:\n",
      " [cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2), cirq.LineQubit(3)]\n",
      "\n",
      "Qubit at position 2:\n",
      " 2\n"
     ]
    }
   ],
   "source": [
    "\"\"\"View some properties of the device.\"\"\"\n",
    "# Display the ion device.\n",
    "print(\"Ion Device:\\n\", ion_device)\n",
    "\n",
    "# Get all qubits in the device.\n",
    "print(\"\\nQubits in the IonDevice:\\n\", sorted(ion_device.qubits))\n",
    "\n",
    "# Get a qubit at a certain position (if present).\n",
    "pos = 2\n",
    "print(f\"\\nQubit at position {pos}:\\n\", ion_device.at(pos))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8d3f1c23ee97"
   },
   "source": [
    "## Native Gate Set"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ptv6T5WH8CLa"
   },
   "source": [
    "An `IonDevice` can implement single-qubit rotations about the $X$, $Y$, and $Z$ axes of the Bloch sphere: namely, `cirq.rx`, `cirq.ry`, and `cirq.rz`. \n",
    "\n",
    "An `IonDevice` can implement the two-qubit Mølmer–Sørensen gate, a rotation about the $XX$ axis in the two-qubit Bloch sphere defined as\n",
    "\n",
    "\\begin{equation}\n",
    "    \\exp(-i t XX) = \\left[ \\begin{matrix}\n",
    "        \\cos t & 0 & 0 & -i \\sin t \\\\\n",
    "        0 & \\cos t & -i \\sin t & 0 \\\\\n",
    "        0 & -i \\sin t & \\cos t & 0 \\\\\n",
    "        -i \\sin t & 0 & 0 & \\cos t\n",
    "    \\end{matrix} \\right] .\n",
    "\\end{equation}\n",
    "\n",
    "The Mølmer–Sørensen gate is defined in Cirq as `cirq.ms`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bb47425324e6"
   },
   "source": [
    "One can check if a given gate is valid with `IonDevice.validate_gate`. This method raises an error if the gate is invalid (not supported by the device) and does nothing if the gate is valid (supported by the device)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "f43884525325"
   },
   "outputs": [],
   "source": [
    "\"\"\"Check if gates are valid. Invalid gates raise a ValueError.\"\"\"\n",
    "# Single-qubit X rotation of any angle is supported.\n",
    "ion_device.validate_gate(cirq.rx(np.pi / 7))\n",
    "\n",
    "# Single-qubit Z rotation of any angle is supported.\n",
    "ion_device.validate_gate(cirq.rz(np.pi / 5))\n",
    "\n",
    "# Mølmer–Sørensen gate of any angle is supported.\n",
    "ion_device.validate_gate(cirq.ms(np.pi / 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "e99a107bb042"
   },
   "source": [
    "One can also validate operations and circuits with `IonDevice.validate_operation` and `IonDevice.validate_circuit`, respectively."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "f9064152b23a"
   },
   "source": [
    "We can get the duration of valid operations as follows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "256eb4b5280a"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "cirq.Duration(micros=10)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"\"\"Get the duration of valid operations.\"\"\"\n",
    "# Duration of a single-qubit operation.\n",
    "ion_device.duration_of(cirq.ry(np.pi / 2).on(ion_device.at(0)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "114420a1171f"
   },
   "source": [
    "## Decomposing Operations and Circuits"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ea89fcfaefde"
   },
   "source": [
    "Operations which are not valid on the device can be decomposed into a set of valid operations. For example, a CNOT gate is not supported but can be implemented with the following decomposition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "id": "217ab5ef3cdd"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequence of IonDevice operations for a CNOT:\n",
      "\n",
      "0: ───Ry(0.5π)───MS(0.25π)───Rx(-0.5π)───Ry(-0.5π)───\n",
      "                 │\n",
      "1: ──────────────MS(0.25π)───Rx(-0.5π)───────────────\n"
     ]
    }
   ],
   "source": [
    "\"\"\"Decompose a CNOT operation into valid IonDevice operations.\"\"\"\n",
    "# Get a CNOT operation.\n",
    "op = cirq.CNOT(ion_device.at(0), ion_device.at(1))\n",
    "\n",
    "# Decompose it for the IonDevice.\n",
    "ion_device_ops = ion_device.decompose_operation(op)\n",
    "\n",
    "# Print the sequence of operations to implement a CNOT.\n",
    "print(\"Sequence of IonDevice operations for a CNOT:\\n\")\n",
    "print(cirq.Circuit(ion_device_ops))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0bb2fb2a1c27"
   },
   "source": [
    "Circuits can also be decomposed in a similar manner using `IonDevice.decompose_circuit`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "Hotk4cHCpXCV"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Circuit to decompose:\n",
      "\n",
      "0: ───H───@───@───\n",
      "          │   │\n",
      "1: ───────X───┼───\n",
      "              │\n",
      "2: ───────────X───\n",
      "\n",
      "IonDevice circuit:\n",
      "\n",
      "0: ───PhX(1)───────────MS(0.25π)───PhX(1)^0.5───────────MS(0.25π)───PhX(-0.5)^0.5───S^-1───\n",
      "                       │                                │\n",
      "1: ────────────────────MS(0.25π)───PhX(1)^0.5───────────┼──────────────────────────────────\n",
      "                                                        │\n",
      "2: ─────────────────────────────────────────────────────MS(0.25π)───PhX(1)^0.5─────────────\n"
     ]
    }
   ],
   "source": [
    "\"\"\"Decompose a circuit into IonDevice operations.\"\"\"\n",
    "# Example circuit to decompose.\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.H(cirq.LineQubit(0)),\n",
    "    cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(1)),\n",
    "    cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(2))\n",
    ")\n",
    "\n",
    "# Display it.\n",
    "print(\"Circuit to decompose:\\n\")\n",
    "print(circuit)\n",
    "\n",
    "# Decompose the circuit.\n",
    "ion_device_circuit = ion_device.decompose_circuit(circuit)\n",
    "\n",
    "# Display the decomposed circuit.\n",
    "print(\"\\nIonDevice circuit:\\n\")\n",
    "print(ion_device_circuit)"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "ion_device.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
